﻿using System;
using System.Collections.Generic;

namespace SceneManager.Components
{
	public class ComponentCollection : IEnumerable<Component>, IDisposable
	{
		#region Variables

		private List<Component> _components;

		#endregion

		#region Constructors

		public ComponentCollection(GameObject parent)
		{
			GameObject = parent;

			_components = new List<Component>();
		}

		#endregion

		#region Properties

		public GameObject GameObject { get; private set; }

		#endregion

		#region Methods

		public IEnumerator<Component> GetEnumerator()
		{
			return _components.GetEnumerator();
		}

		System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
		{
			return _components.GetEnumerator();
		}

		public void Dispose()
		{
			GameObject = null;
		}

		public Component Find(Type componentType)
		{
			foreach (var component in _components)
			{
				if (component.GetType() == componentType)
				{
					return component;
				}
			}
			return null;
		}

		public T Find<T>()
			where T : Component
		{
			foreach (var component in _components)
			{
				if (component is T)
				{
					return (T)component;
				}
			}
			return null;
		}

		public bool IsDefined(Type componentType)
		{
			return Find(componentType) != null;
		}

		public bool IsDefined<T>()
			where T : Component
		{
			return Find<T>() != null;
		}

		/// <summary>
		/// Add a component to the collection and call it's LoadContent method.
		/// </summary>
		public T Add<T>()
			where T : Component
		{
			if (IsDefined<T>())
			{
				throw new InvalidOperationException(string.Format("{0} is already defined.", typeof(T).Name));
			}
			var component = (T)Activator.CreateInstance(typeof(T), this);
			_components.Add(component);
			component.LoadContent();
			return component;
		}

		public Component Add(Type componentType)
		{
			if (IsDefined(componentType))
			{
				throw new InvalidOperationException(string.Format("{0} is already defined.", componentType.Name));
			}

			var component = Activator.CreateInstance(componentType, this) as Component;
			_components.Add(component);
			component.LoadContent();
			return component;
		}

		/// <summary>
		/// Call the component's UnloadContent method and remove it from the collection.
		/// </summary>
		/// <typeparam name="T"></typeparam>
		public void Remove<T>()
			where T : Component
		{
			if (!IsDefined<T>())
			{
				throw new InvalidOperationException(string.Format("{0} is not defined.", typeof(T).Name));
			}
			T component = Find<T>();
			component.UnloadContent();
			_components.Remove(component);
		}

		#endregion
	}
}